/************************************************
*    EP1- Intr. Prog. Paralela e distribuída    *
*  Implemetação de um Raytracing otimizado e    *
*  paralelo.                                    *
*                                               *
*  membros:                                     *
*         Erika                                 *
*         Luís Henrique                         *
*         Paulo Victor                          *
*                                               *
* Qua Set 29 11:40:19 BRT 2010                  *
************************************************/


#include <stdio.h>
#include <math.h>
#include <omp.h>

#define produto_vetorial_x(a,b) ((a.sentido.y-a.origem.y)*(b.sentido.z-b.origem.z)-(a.sentido.z-a.origem.z)*(b.sentido.y-b.origem.y))
#define produto_vetorial_y(a,b) ((a.sentido.z-a.origem.z)*(b.sentido.x-b.origem.x)-(a.sentido.x-a.origem.x)*(b.sentido.z-b.origem.z))
#define produto_vetorial_z(a,b) ((a.sentido.x-a.origem.x)*(b.sentido.y-b.origem.y)-(a.sentido.y-a.origem.y)*(b.sentido.x-b.origem.x))
#define MIN(a,b) (a<b)? a:b
#define MAX(a,b,c) (a>b&&a>c)? a :((b>c)? b:c)
#define norma(a) ((a.sentido.x-a.origem.x)*(a.sentido.x-a.origem.x) + (a.sentido.y-a.origem.y)*(a.sentido.y-a.origem.y) + (a.sentido.z-a.origem.z)*(a.sentido.z-a.origem.z))
#define ZERO 0.0001

typedef struct cor{
    double R;
    double G;
    double B;
} Cor;

// Estrutura do tipo: ponto
typedef struct ponto{
    double x;
    double y;
    double z;
} Ponto;

// Estrutura do tipo: triângulo
typedef struct triangulo{
    Ponto p1;
    Ponto p2;
    Ponto p3;

    Cor luminosidade;
    Cor reflexao;
    Cor transparencia;
    double refracao;
} Triangulo;

//definindo um plano pelos pontos Ax+By+Cz=D
typedef struct plano{
    double A;
    double B;
    double C;
    double D;
} Plano;

// Estrutura do tipo: raio
typedef struct raio{
    Ponto origem;
    Ponto sentido;

    Cor fator_cor;
    Ponto pixel;
    int geracao;
    int dentro;
}Raio;

// Estrutura do tipo: janela
typedef struct janela{
    Ponto p1; //canto inferior esquerdo
    Ponto p2; //canto superior esquerdo
    Ponto p3; //canto superior direito
    Ponto p4; //canto inferior direito

} Janela;

// Estrutura do tipo: esfera
typedef struct esfera{
    Ponto centro;
    double raio;

    double raio_quadrado; // raio*raio
    double centro_quadrado; // centro.x*centro.x + centro.y*centro.y + centro.z*centro.z

    Cor luminosidade;
    Cor reflexao;
    Cor transparencia;
    double refracao;
}Esfera;

double produto_escalar_raios(Raio raio1,Raio raio2){
    return    (raio1.sentido.x-raio1.origem.x)*(raio2.sentido.x-raio2.origem.x)
            + (raio1.sentido.y-raio1.origem.y)*(raio2.sentido.y-raio2.origem.y)
            + (raio1.sentido.z-raio1.origem.z)*(raio2.sentido.z-raio2.origem.z);
}

/*** funções de interseção ***/

/*** Raio X Esfera ***/

/*verifica a interseção entre o raio e a esfera.
  raio: r.origem + t * (r.sentido - r.origem)
  esfera: (X-e.centro.x)² + (Y-e.centro.y)² + (Z-e.centro.z)² = R²

  Substitui os pontos do raio na equação da esfera e retorna, caso haja, o ponto de intersecao.
*/
double intersecta_raio_esfera(Raio r, Esfera e,Ponto *intersecao){
    double a,b,c, t1,t2, delta;

    double dx = r.sentido.x - r.origem.x;
    double dy = r.sentido.y - r.origem.y;
    double dz = r.sentido.z - r.origem.z;

    double ox = r.origem.x;
    double oy = r.origem.y;
    double oz = r.origem.z;

    double sx = e.centro.x ;
    double sy = e.centro.y ;
    double sz = e.centro.z ;
    double ra = e.raio_quadrado;

    a = dx*dx + dy*dy + dz*dz;
    b = 2 * (dx * ( ox - sx ) + dy * ( oy - sy ) + dz * ( oz - sz ));
    c = (ox - sx)*(ox - sx) + (oy - sy)*(oy - sy) + (oz - sz)*(oz - sz) - ra;

    delta = b*b - 4*a*c;

    //Se houver solução, há ponto de interseção
    if (delta >= 0){
        t1 = (-b + sqrt(delta)) / (2*a);
        t2 = (-b - sqrt(delta)) / (2*a);

        if(t2 > ZERO){
            intersecao->x = r.origem.x + t2*dx;
            intersecao->y = r.origem.y + t2*dy;
            intersecao->z = r.origem.z + t2*dz;
            return t2;
        }
        else if(t1 > ZERO){
            intersecao->x = r.origem.x + t1*dx;
            intersecao->y = r.origem.y + t1*dy;
            intersecao->z = r.origem.z + t1*dz;
            return t1;
        }
    }

    return -1;
}

double intersecta_raio_triangulo(Raio r, Triangulo T, Ponto *intersecao){
    double A,B,C, t;

    double x1,x2,x3,y1,y2,y3,z1,z2,z3;

    double denominador;

    x1 = T.p1.x;
    x2 = T.p2.x;
    x3 = T.p3.x;

    y1 = T.p1.y;
    y2 = T.p2.y;
    y3 = T.p3.y;

    z1 = T.p1.z;
    z2 = T.p2.z;
    z3 = T.p3.z;

    A = (y2-y1)*(z3-z2) - (y3-y2)*(z2-z1);
    B = (x3-x2)*(z2-z1) - (x2-x1)*(z3-z2);
    C = (x2-x1)*(y3-y2) - (x3-x2)*(y2-y1);

    denominador = A*(r.sentido.x-r.origem.x) + B*(r.sentido.y-r.origem.y) + C*(r.sentido.z-r.origem.z);

    if(denominador != 0){
            t = (A*(x1-r.origem.x) + B*(y1-r.origem.y) + C*(z1-r.origem.z))/denominador;

            if(t<=ZERO) return -1;

            intersecao->x = r.origem.x + t*(r.sentido.x-r.origem.x);
            intersecao->y = r.origem.y + t*(r.sentido.y-r.origem.y);
            intersecao->z = r.origem.z + t*(r.sentido.z-r.origem.z);

            Raio aux, aux2;
            aux.origem = T.p1;
            aux.sentido = T.p2;
            aux2.origem = T.p1;
            aux2.sentido.x = intersecao->x;
            aux2.sentido.y = intersecao->y;
            aux2.sentido.z = intersecao->z;

            if(A*(produto_vetorial_x(aux,aux2)) + B*(produto_vetorial_y(aux,aux2)) 
				+ C*(produto_vetorial_z(aux,aux2)) >= 0){
                aux.origem = T.p2;
                aux.sentido = T.p3;
                aux2.origem = T.p2;

                if(A*(produto_vetorial_x(aux,aux2)) + B*(produto_vetorial_y(aux,aux2)) 
					+ C*(produto_vetorial_z(aux,aux2)) >= 0){
                    aux.origem = T.p3;
                    aux.sentido = T.p1;
                    aux2.origem = T.p3;

                    if(A*(produto_vetorial_x(aux,aux2)) + B*(produto_vetorial_y(aux,aux2))
						+ C*(produto_vetorial_z(aux,aux2)) >= 0){
                        return t;
                    }

                }
            }
    }
    return -1;
}
// GLOBAL

int objeto;
int qtd_objetos;
double limiar;
Cor fator_cor;
Ponto visao;
Janela janela;
Ponto passo_horizontal, passo_vertical;
Esfera esferas[100];
Triangulo triangulos[100];
int numero_triangulos = 0;
int numero_esferas = 0;
int numero_cilindros = 0;
int numero_cones = 0;
Raio raios[1000000];
int marcraios[100000];
int fraios=0;
int iraios=0;
Ponto ponto_intersecao;
Ponto ponto_intersecao_perto;
int iteracao, maxiteracao;
int maxgeracoes = 0;
double aux;
int largura, altura; //em pixels

FILE *saida;

void adiciona_raio(Raio v){
    raios[fraios++] = v;
    if (fraios > 1000000){
     fraios = 0;
     printf("fail");
    }
}

/*** RAYTRACING ***/

void ray_tracing(){

    int i =0;
    Raio v;

    v.dentro = 0;

    v.origem.x = visao.x;
    v.origem.y = visao.y;
    v.origem.z = visao.z;

    v.fator_cor.R = fator_cor.R;
    v.fator_cor.G = fator_cor.G;
    v.fator_cor.B = fator_cor.B;

    v.geracao = 0;

    Ponto pontoAtual;
    Ponto pixel_atual;

    double d;

   
   maxiteracao = largura * altura;
   
   #pragma opm parallel for num_threads(8)
    for(iteracao =1; iteracao <= maxiteracao; iteracao++){
        //calcula o ponto atual (x,y,z) na janela a ser calculado na iteracao corrente
        aux = (int)( (iteracao-1)/largura );
        pontoAtual.x = janela.p2.x + aux*passo_vertical.x;
        pontoAtual.y = janela.p2.y + aux*passo_vertical.y;
        pontoAtual.z = janela.p2.z + aux*passo_vertical.z;
        aux = (iteracao % largura) - 1; if(aux == -1) aux = largura-1;
        pontoAtual.x +=  aux*passo_horizontal.x;
        pontoAtual.y +=  aux*passo_horizontal.y;
        pontoAtual.z +=  aux*passo_horizontal.z;
        //----------------------------------------------------------------------------

        v.sentido.x = pontoAtual.x;// - v.origem.x;
        v.sentido.y = pontoAtual.y;// - v.origem.y;
        v.sentido.z = pontoAtual.z;// - v.origem.z;

        pixel_atual.x = 0;
        pixel_atual.y = 0;
        pixel_atual.z = 0;

        iraios = fraios = 0;
        adiciona_raio(v);

        while(iraios < fraios){
            int primeira_esfera       = -1;
            int primeiro_triangulo    = -1;
            double menor_distancia    = -1;

            //testa intersecao com esferas---------------------------------------------
            for (i=0; i<numero_esferas; i++){
                d = intersecta_raio_esfera(raios[iraios],esferas[i],&ponto_intersecao);
                if(d>0 && (d<menor_distancia || menor_distancia==-1)) {
                    menor_distancia = d;
                    primeira_esfera = i;
                    ponto_intersecao_perto = ponto_intersecao;
                }
            }
            //-------------------------------------------------------------------------

            //testa intersecao com triangulos------------------------------------------
            for (i=0; i<numero_triangulos; i++){
                d=intersecta_raio_triangulo(raios[iraios],triangulos[i],&ponto_intersecao);
                if(d>0 && (d<menor_distancia || menor_distancia==-1)) {
                    menor_distancia = d;
                    primeiro_triangulo = i;
                    ponto_intersecao_perto = ponto_intersecao;
                }
            }
            //-------------------------------------------------------------------------

            if(primeira_esfera >= 0 && primeiro_triangulo<0){
                Raio normal;
                normal.origem  = esferas[primeira_esfera].centro;
                normal.sentido = ponto_intersecao_perto;

                double cos = produto_escalar_raios(raios[iraios],normal)/( sqrt(norma(raios[iraios])) * sqrt(norma(normal)) );

                pixel_atual.x  +=  sqrt(cos*cos) *  raios[iraios].fator_cor.R * (esferas[primeira_esfera].luminosidade.R);
                pixel_atual.y  +=  sqrt(cos*cos) *  raios[iraios].fator_cor.G * (esferas[primeira_esfera].luminosidade.G);
                pixel_atual.z  +=  sqrt(cos*cos) *  raios[iraios].fator_cor.B * (esferas[primeira_esfera].luminosidade.B);

                Raio refletido;

                refletido.dentro = 0;

                //calcula geracao e fator de cor do raio refletido
                refletido.geracao = raios[iraios].geracao + 1;

                //calcula fator de cor do raio refletido
                refletido.fator_cor.R = raios[iraios].fator_cor.R * (esferas[primeira_esfera].reflexao.R);
                refletido.fator_cor.G = raios[iraios].fator_cor.G * (esferas[primeira_esfera].reflexao.G);
                refletido.fator_cor.B = raios[iraios].fator_cor.B * (esferas[primeira_esfera].reflexao.B);

                if(refletido.geracao <= maxgeracoes 
					&& MAX(refletido.fator_cor.R,refletido.fator_cor.G,refletido.fator_cor.B)>=limiar){
                    refletido.origem = ponto_intersecao_perto;

                    double dot_product  = (normal.sentido.x-normal.origem.x)*(raios[iraios].sentido.x-raios[iraios].origem.x);
                           dot_product += (normal.sentido.y-normal.origem.y)*(raios[iraios].sentido.y-raios[iraios].origem.y);
                           dot_product += (normal.sentido.z-normal.origem.z)*(raios[iraios].sentido.z-raios[iraios].origem.z);

                    //Raio incidente: V
                    //Raio Refletido: RI
                    //Normal: N
                    // RI = V - 2*N*dot_product(N,V)
                    refletido.sentido.x = raios[iraios].sentido.x-raios[iraios].origem.x 
						- 2*(normal.sentido.x-normal.origem.x)*dot_product + refletido.origem.x;

                    refletido.sentido.y = raios[iraios].sentido.y-raios[iraios].origem.y 
						- 2*(normal.sentido.y-normal.origem.y)*dot_product + refletido.origem.y;

                    refletido.sentido.z = raios[iraios].sentido.z-raios[iraios].origem.z 
						- 2*(normal.sentido.z-normal.origem.z)*dot_product + refletido.origem.z;

                   #pragma opm critical
                   {
				     adiciona_raio(refletido);
				   }  
                }

                Raio refratado;

                if(raios[iraios].dentro == 0) refratado.dentro = 1;
                else refratado.dentro = 0;

                //calcula geracao e fator de cor do raio refratado
                refratado.geracao = raios[iraios].geracao + 1;

                //calcula fator de cor do raio refratado
                if(refratado.dentro == 1){
                    refratado.fator_cor.R = raios[iraios].fator_cor.R * (esferas[primeira_esfera].transparencia.R);
                    refratado.fator_cor.G = raios[iraios].fator_cor.G * (esferas[primeira_esfera].transparencia.G);
                    refratado.fator_cor.B = raios[iraios].fator_cor.B * (esferas[primeira_esfera].transparencia.B);
                } else {
                    refratado.fator_cor.R = raios[iraios].fator_cor.R;
                    refratado.fator_cor.G = raios[iraios].fator_cor.G;
                    refratado.fator_cor.B = raios[iraios].fator_cor.B;
                }
                if(refratado.geracao <= maxgeracoes 
					&& MAX(refratado.fator_cor.R,refratado.fator_cor.G,refratado.fator_cor.B)>=limiar){
                    refratado.origem = ponto_intersecao_perto;

                    double dot_product  = (normal.sentido.x-normal.origem.x)*(raios[iraios].sentido.x-raios[iraios].origem.x);
                           dot_product += (normal.sentido.y-normal.origem.y)*(raios[iraios].sentido.y-raios[iraios].origem.y);
                           dot_product += (normal.sentido.z-normal.origem.z)*(raios[iraios].sentido.z-raios[iraios].origem.z);

                    //Raio incidente: V
                    //Raio Refratado: Rr
                    //Normal: N
                    //n = indice de refracao relativo dos meios
                    //c1 = -dot_product( N, V )
                    //c2 = sqrt( 1 - n*n * (1 - c1*c1) )
                    // Rr = (n * V) + (n * c1 - c2)*N
                    double n 
						= (refratado.dentro==0||esferas[primeira_esfera].refracao==0)? 
							esferas[primeira_esfera].refracao : 1/esferas[primeira_esfera].refracao;

                    double c2 = sqrt(1 - n*n*(1-dot_product*dot_product) );

                    refratado.sentido.x = (n * (raios[iraios].sentido.x-raios[iraios].origem.x)) 
						+ (n * (-dot_product) - c2)*(normal.sentido.x-normal.origem.x) + refratado.origem.x;

                    refratado.sentido.y = (n * (raios[iraios].sentido.y-raios[iraios].origem.y)) 
						+ (n * (-dot_product) - c2)*(normal.sentido.y-normal.origem.y) + refratado.origem.y;

                    refratado.sentido.z = (n * (raios[iraios].sentido.z-raios[iraios].origem.z)) 
						+ (n * (-dot_product) - c2)*(normal.sentido.z-normal.origem.z) + refratado.origem.z;
                   
				   #pragma opm critical
                   {
                   adiciona_raio(refratado);
		   			}
                }
            } else if(primeiro_triangulo>=0){

                Raio normal;
                double x1,x2,x3,y1,y2,y3,z1,z2,z3;

                x1 = triangulos[primeiro_triangulo].p1.x;
                x2 = triangulos[primeiro_triangulo].p2.x;
                x3 = triangulos[primeiro_triangulo].p3.x;

                y1 = triangulos[primeiro_triangulo].p1.y;
                y2 = triangulos[primeiro_triangulo].p2.y;
                y3 = triangulos[primeiro_triangulo].p3.y;

                z1 = triangulos[primeiro_triangulo].p1.z;
                z2 = triangulos[primeiro_triangulo].p2.z;
                z3 = triangulos[primeiro_triangulo].p3.z;

                normal.origem =  ponto_intersecao_perto;

                normal.sentido.x = (y2-y1)*(z3-z2) - (y3-y2)*(z2-z1) + ponto_intersecao_perto.x;
                normal.sentido.y = (x3-x2)*(z2-z1) - (x2-x1)*(z3-z2) + ponto_intersecao_perto.y;
                normal.sentido.z = (x2-x1)*(y3-y2) - (x3-x2)*(y2-y1) + ponto_intersecao_perto.z;

                double cos = produto_escalar_raios(raios[iraios],normal)/( sqrt(norma(raios[iraios])) * sqrt(norma(normal)) );

                pixel_atual.x  += sqrt(cos*cos) * raios[iraios].fator_cor.R * (triangulos[primeiro_triangulo].luminosidade.R);
                pixel_atual.y  += sqrt(cos*cos) * raios[iraios].fator_cor.G * (triangulos[primeiro_triangulo].luminosidade.G);
                pixel_atual.z  += sqrt(cos*cos) * raios[iraios].fator_cor.B * (triangulos[primeiro_triangulo].luminosidade.B);

                Raio refletido;
                //calcula geracao e fator de cor do raio refletido
                refletido.geracao = raios[iraios].geracao + 1;

                //calcula fator de cor do raio refletido
                refletido.fator_cor.R = raios[iraios].fator_cor.R * (triangulos[primeiro_triangulo].reflexao.R);
                refletido.fator_cor.G = raios[iraios].fator_cor.G * (triangulos[primeiro_triangulo].reflexao.G);
                refletido.fator_cor.B = raios[iraios].fator_cor.B * (triangulos[primeiro_triangulo].reflexao.B);

                if(refletido.geracao <= maxgeracoes 
					&& MAX(refletido.fator_cor.R,refletido.fator_cor.G,refletido.fator_cor.B) >=limiar){
                    refletido.origem = ponto_intersecao_perto;

                    double dot_product  = (normal.sentido.x-normal.origem.x)*(raios[iraios].sentido.x-raios[iraios].origem.x);
                           dot_product += (normal.sentido.y-normal.origem.y)*(raios[iraios].sentido.y-raios[iraios].origem.y);
                           dot_product += (normal.sentido.z-normal.origem.z)*(raios[iraios].sentido.z-raios[iraios].origem.z);

                    //Raio incidente: V
                    //Raio Refletido: RI
                    //Normal: N
                    // RI = V - 2*N*dot_product(N,V)
                    refletido.sentido.x = raios[iraios].sentido.x-raios[iraios].origem.x 
						- 2*(normal.sentido.x-normal.origem.x)*dot_product + refletido.origem.x;

                    refletido.sentido.y = raios[iraios].sentido.y-raios[iraios].origem.y 
						- 2*(normal.sentido.y-normal.origem.y)*dot_product + refletido.origem.y;

                    refletido.sentido.z = raios[iraios].sentido.z-raios[iraios].origem.z 
						- 2*(normal.sentido.z-normal.origem.z)*dot_product + refletido.origem.z;

                   #pragma opm critical
                   {
					   adiciona_raio(refletido);
				   }
                }

                Raio refratado;

                if(raios[iraios].dentro == 0) refratado.dentro = 0;
                else refratado.dentro = 1;

                //calcula geracao e fator de cor do raio refratado
                refratado.geracao = raios[iraios].geracao + 1;

                //calcula fator de cor do raio refratado
                refratado.fator_cor.R = raios[iraios].fator_cor.R * (triangulos[primeiro_triangulo].transparencia.R);
                refratado.fator_cor.G = raios[iraios].fator_cor.G * (triangulos[primeiro_triangulo].transparencia.G);
                refratado.fator_cor.B = raios[iraios].fator_cor.B * (triangulos[primeiro_triangulo].transparencia.B);


                if(refratado.geracao <= maxgeracoes 
					&& MAX(refratado.fator_cor.R,refratado.fator_cor.G,refratado.fator_cor.B)>=limiar){
                    refratado.origem = ponto_intersecao_perto;

                    double dot_product  = (normal.sentido.x-normal.origem.x)*(raios[iraios].sentido.x-raios[iraios].origem.x);
                           dot_product += (normal.sentido.y-normal.origem.y)*(raios[iraios].sentido.y-raios[iraios].origem.y);
                           dot_product += (normal.sentido.z-normal.origem.z)*(raios[iraios].sentido.z-raios[iraios].origem.z);

                    //Raio incidente: V
                    //Raio Refratado: Rr
                    //Normal: N
                    //n = indice de refracao relativo dos meios
                    //c1 = -dot_product( N, V )
                    //c2 = sqrt( 1 - n*n * (1 - c1*c1) )
                    // Rr = (n * V) + (n * c1 - c2)*N
                    double n =  triangulos[primeiro_triangulo].refracao;
                    double c2 = sqrt(1 - n*n*(1-dot_product*dot_product) );
                    refratado.sentido.x = (n * (raios[iraios].sentido.x-raios[iraios].origem.x)) 
						+ (n * (-dot_product) - c2)*(normal.sentido.x-normal.origem.x) + refratado.origem.x;

                    refratado.sentido.y = (n * (raios[iraios].sentido.y-raios[iraios].origem.y)) 
						+ (n * (-dot_product) - c2)*(normal.sentido.y-normal.origem.y) + refratado.origem.y;

                    refratado.sentido.z = (n * (raios[iraios].sentido.z-raios[iraios].origem.z)) 
						+ (n * (-dot_product) - c2)*(normal.sentido.z-normal.origem.z) + refratado.origem.z;
                      
                    #pragma opm critial
				    {
	                    adiciona_raio(refratado);
				    }
                }
            }

            iraios++;
        }

        fprintf(saida,"%d %d %d ",MIN(((int)(pixel_atual.x*255)),255),
			MIN((int)(pixel_atual.y*255),255),MIN((int)(pixel_atual.z*255),255));
       //iteracao++;i
    }
}

//MAIN

int main(int argc, char *argv[]){

    //Leitura do Arquivo com Descrição do Mundo------------
    FILE *p = fopen(argv[1],"r");
    fscanf(p,"%d",&qtd_objetos);
    int cont = 0;
    while(cont < qtd_objetos){
        fscanf(p,"%d",&objeto);
        if (objeto == 0){ // triangulo
            fscanf(p,"%lf %lf %lf", &triangulos[numero_triangulos].luminosidade.R,  
				&triangulos[numero_triangulos].luminosidade.G,  &triangulos[numero_triangulos].luminosidade.B);

            fscanf(p,"%lf %lf %lf", &triangulos[numero_triangulos].reflexao.R,      
				&triangulos[numero_triangulos].reflexao.G,      &triangulos[numero_triangulos].reflexao.B);

            fscanf(p,"%lf %lf %lf", &triangulos[numero_triangulos].transparencia.R, 
				&triangulos[numero_triangulos].transparencia.G, &triangulos[numero_triangulos].transparencia.B );

            fscanf(p,"%lf", &triangulos[numero_triangulos].refracao);

            //Pontos do triangulo dados em sentido anti-horario quando olhados pelo lado externo da face
            fscanf(p,"%lf %lf %lf", &triangulos[numero_triangulos].p1.x, &triangulos[numero_triangulos].p1.y, 
				&triangulos[numero_triangulos].p1.z);

            fscanf(p,"%lf %lf %lf", &triangulos[numero_triangulos].p2.x, &triangulos[numero_triangulos].p2.y,            
				&triangulos[numero_triangulos].p2.z);

            fscanf(p,"%lf %lf %lf", &triangulos[numero_triangulos].p3.x, &triangulos[numero_triangulos].p3.y,            
				&triangulos[numero_triangulos].p3.z);

            numero_triangulos++;
        } else if(objeto == 1){ //esfera
            fscanf(p,"%lf %lf %lf",     &esferas[numero_esferas].luminosidade.R,    &esferas[numero_esferas].luminosidade.G,  
				&esferas[numero_esferas].luminosidade.B);

            fscanf(p,"%lf %lf %lf",     &esferas[numero_esferas].reflexao.R,        &esferas[numero_esferas].reflexao.G,      
				&esferas[numero_esferas].reflexao.B);

            fscanf(p,"%lf %lf %lf",     &esferas[numero_esferas].transparencia.R,   &esferas[numero_esferas].transparencia.G, 
				&esferas[numero_esferas].transparencia.B);

            fscanf(p,"%lf",             &esferas[numero_esferas].refracao);

            fscanf(p,"%lf %lf %lf %lf", &esferas[numero_esferas].raio,              &esferas[numero_esferas].centro.x,        
				&esferas[numero_esferas].centro.y,       &esferas[numero_esferas].centro.z);

            esferas[numero_esferas].raio_quadrado    = esferas[numero_esferas].raio  *  esferas[numero_esferas].raio;
            esferas[numero_esferas].centro_quadrado  = esferas[numero_esferas].centro.x*esferas[numero_esferas].centro.x;
            esferas[numero_esferas].centro_quadrado += esferas[numero_esferas].centro.y*esferas[numero_esferas].centro.y;
            esferas[numero_esferas].centro_quadrado += esferas[numero_esferas].centro.z*esferas[numero_esferas].centro.z;

            numero_esferas++;
        }
        else if(objeto == 2){ //cilindro
            numero_cilindros++;
        }
        else if(objeto == 3){ //cone
            numero_cones++;
        }

        cont++;
    }
    fclose(p);
    //Fim da leitura do Arquivo com Descrição do Mundo-----

    //Leitura do Arquivo com Descrição da Vista------------
    p = fopen(argv[2],"r");
    fscanf(p,"%lf %lf %lf", &visao.x,      &visao.y,      &visao.z    );
    fscanf(p,"%lf %lf %lf", &janela.p1.x,  &janela.p1.y,  &janela.p1.z);
    fscanf(p,"%lf %lf %lf", &janela.p2.x,  &janela.p2.y,  &janela.p2.z);
    fscanf(p,"%lf %lf %lf", &janela.p3.x,  &janela.p3.y,  &janela.p3.z);
    fscanf(p,"%lf %lf %lf", &janela.p4.x,  &janela.p4.y,  &janela.p4.z);
    //fscanf(p,"%lf %lf %lf", &fator_cor.R,  &fator_cor.G,  &fator_cor.B);
    fator_cor.R = 1;
    fator_cor.G = 1;
    fator_cor.B = 1;
    fclose(p);
    //Fim da leitura do Arquivo com Descrição da Vista----

    saida = fopen(argv[3],"w");

    //Recebe largura e altura da imagem por parâmetros----
    sscanf(argv[4],"%d",&largura);
    sscanf(argv[5],"%d",&altura);
    //----------------------------------------------------

    printf ("%d %d",largura,altura);
    passo_horizontal.x = (janela.p3.x - janela.p2.x) / (largura-1);
    passo_horizontal.y = (janela.p3.y - janela.p2.y) / (largura-1);
    passo_horizontal.z = (janela.p3.z - janela.p2.z) / (largura-1);

    passo_vertical.x   = (janela.p1.x - janela.p2.x) / (altura-1);
    passo_vertical.y   = (janela.p1.y - janela.p2.y) / (altura-1);
    passo_vertical.z   = (janela.p1.z - janela.p2.z) / (altura-1);

    fprintf(saida,"P3                         \n");
    fprintf(saida,"#saida.pnm                 \n");
    fprintf(saida,"%d %d                      \n",largura,altura);
    fprintf(saida,"255                        \n");

    sscanf(argv[6],"%lf",&limiar);
    sscanf(argv[7],"%d" ,&maxgeracoes);

    ray_tracing();
    fclose(saida);

    return 0;
}
